//
// Created by miaomiaole on 2024/1/27.
//
#include <opencv2\opencv.hpp>

#include <iostream>
#include <opencv2\imgproc\types_c.h> //for CV_RGB2GRAY
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace cv;

using namespace std;

void diffOperation() {
    auto source = imread("./IMG_20161003_182919.jpg");
    namedWindow("source", WINDOW_NORMAL);
    imshow("source", source);

    Mat edgeX(source.size(), source.type());

    Mat edgeY(source.size(), source.type());

    auto tempImage = source.clone();
    int nRows = tempImage.rows;
    int nCols = tempImage.cols;
    for (int i = 0; i < nRows - 1; i++) {
        for (int j = 0; j < nCols - 1; j++) {
            // 计算垂直边边缘
            edgeX.at<uchar>(i, j) =
                    abs(tempImage.at<uchar>(i + 1, j) -
                        tempImage.at<uchar>(i, j));
            // 计算水平边缘
            edgeY.at<uchar>(i, j) =
                    abs(tempImage.at<uchar>(i, j + 1) -
                        tempImage.at<uchar>(i, j));
        }
    }

    namedWindow("edgeXImage", 0);
    namedWindow("edgeYImage", 0);
    imshow("edgeXImage", edgeX);
    imshow("edgeYImage", edgeY);


    waitKey(0);
}


void roberts() {
    auto source = imread("./IMG_20161003_182919.jpg");
    namedWindow("source", WINDOW_NORMAL);
    imshow("source", source);

    Mat srcGray;
    cvtColor(source, srcGray, CV_BGR2GRAY);
    //高斯滤波
    GaussianBlur(srcGray, srcGray, Size(3, 3),
                 0, 0, BORDER_DEFAULT);

    srcGray = source.clone();
    int nRows = srcGray.rows;
    int nCols = srcGray.cols;
    for (int i = 0; i < nRows - 1; i++) {
        for (int j = 0; j < nCols - 1; j++) {
            //根据公式计算
            int t1 = (source.at<uchar>(i, j) -
                      source.at<uchar>(i + 1, j + 1)) *
                     (source.at<uchar>(i, j) -
                      source.at<uchar>(i + 1, j + 1));
            int t2 = (source.at<uchar>(i + 1, j) -
                      source.at<uchar>(i, j + 1)) *
                     (source.at<uchar>(i + 1, j) -
                      source.at<uchar>(i, j + 1));
            //计算g（x,y）
            srcGray.at<uchar>(i, j) = (uchar) sqrt(t1 + t2);
        }
    }

    namedWindow("srcGray", WINDOW_NORMAL);
    imshow("srcGray", srcGray);
    waitKey(0);
}


void getPrewitt_oper(Mat &prewitt_x, Mat &prewitt_y, Mat &prewitt_diagonal, Mat &prewitt_diagonal_2) {
    //水平方向
    prewitt_x = (cv::Mat_<float>(3, 3) << -1, -1, -1, 0, 0, 0, 1, 1, 1);
    //垂直方向
    prewitt_y = (cv::Mat_<float>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);
    //对角135°
    prewitt_diagonal = (cv::Mat_<float>(3, 3) << 0, 1, 1, -1, 0, 1, -1, -1, 0);
    //对角45°
    prewitt_diagonal_2 = (cv::Mat_<float>(3, 3) << -1, -1, 0, -1, 0, 1, 0, 1, 1);

    //逆时针反转180°得到卷积核
    cv::flip(prewitt_x, prewitt_x, -1);
    cv::flip(prewitt_y, prewitt_y, -1);
    cv::flip(prewitt_diagonal, prewitt_diagonal, -1);
    cv::flip(prewitt_diagonal_2, prewitt_diagonal_2, -1);
}

void sobel() {
    auto img = imread("./IMG_20161003_182919.jpg", IMREAD_ANYCOLOR);

    namedWindow("source", WINDOW_NORMAL);
    imshow("source", img);


    Mat resultX, resultY, resultXY;
    // 边缘检测 利用像素周围的灰度加权（导数求极值）

    //X方向一阶边缘
    Sobel(img, resultX, CV_16S, 2, 0, 1);

    convertScaleAbs(resultX, resultX);
    //Y方向一阶边缘
    Sobel(img, resultY, CV_16S, 0, 1, 3);

    convertScaleAbs(resultY, resultY);

    resultXY = resultX + resultY;//整幅图像的一阶边缘

    //显示图像

    namedWindow("resultX", WINDOW_NORMAL);
    namedWindow("resultY", WINDOW_NORMAL);
    namedWindow("resultXY", WINDOW_NORMAL);

    imshow("resultX", resultX);
    imshow("resultY", resultY);
    imshow("resultXY", resultXY);

    imwrite("./resultX.jpg", resultX);
    imwrite("./resultY.jpg", resultY);
    imwrite("./resultXY.jpg", resultXY);
    waitKey(0);
}

// 普利维特 （一阶微分算子)
void prewitt() {

    int ddepth = 0;
    double delta = 0;
    int borderType = cv::BORDER_DEFAULT;


    auto source = imread("./IMG_20161003_182919.jpg");
    namedWindow("source", WINDOW_NORMAL);
    imshow("source", source);
    Mat prewitt_x, prewitt_y, prewitt_diagonal, prewitt_diagonal_2;

    getPrewitt_oper(prewitt_x, prewitt_y, prewitt_diagonal, prewitt_diagonal_2);

    Mat dst_x, dst_y, dst_x_y, dst_xy;

    // 卷积得到水平方向边缘
    filter2D(source, dst_x, ddepth, prewitt_x, Point(-1, -1), delta, borderType);
    // 卷积得到垂直方向边缘
    filter2D(source, dst_y, ddepth, prewitt_x, Point(-1, -1), delta, borderType);

    filter2D(source, dst_x_y, ddepth, prewitt_diagonal, cv::Point(-1, -1), delta, borderType);

    filter2D(source, dst_xy, ddepth, prewitt_diagonal_2, cv::Point(-1, -1), delta, borderType);

    //边缘强度 求绝对值并转为无符号8位图
    convertScaleAbs(dst_x, dst_x);
    convertScaleAbs(dst_y, dst_y);
    convertScaleAbs(dst_x_y, dst_x_y);
    convertScaleAbs(dst_xy, dst_xy);

    auto result = dst_x + dst_y;

    namedWindow("result", WINDOW_NORMAL);
    imshow("result", result);


    namedWindow("dst_x", WINDOW_NORMAL);
    imshow("dst_x", dst_x);

    namedWindow("dst_y", WINDOW_NORMAL);
    imshow("dst_y", dst_y);


    namedWindow("dst_x_y", WINDOW_NORMAL);
    imshow("dst_x_y", dst_x_y);


    namedWindow("dst_xy", WINDOW_NORMAL);
    imshow("dst_xy", dst_xy);

    waitKey(0);
}


void gaussian_edge() {

}

int main() {
    // diffOperation();
    // roberts();
    // sobel();
    prewitt();
}